package com.google.code

object Node {
  def apply(nodeName: String, attributes: List[Attribute], parent: Option[Node], children: List[XmlNode]) =
    new Node(nodeName, attributes, parent, children)

}

class Node(val nodeName: String, val attributes: List[Attribute],
           val parent: Option[Node], ch: List[XmlNode]) extends XmlNode {

  val children = ch map (_ changeParent Some(this))

  def addChild(child: XmlNode) =
    Node(nodeName, attributes, parent, children :+ child)

  def removeChild(child: XmlNode) =
    Node(nodeName, attributes, parent, children.filterNot(_ equals child))

  def changeChild(child: Node) =
    Node(nodeName, attributes, parent, children map {
      case n: Node =>
        if(n.nodeName equals child.nodeName) child
        else n
      case c: Comment => c
    })

  def addAttribute(attribute: Attribute) =
    Node(nodeName, attributes :+ attribute, parent, children)

  def removeAttribute(attribute: Attribute) =
    Node(nodeName, attributes.filterNot(_ equals attribute), parent, children)

  override def changeParent(newParent: Option[Node]): Node =
    Node(nodeName, attributes, newParent, children)

  override def foldLeft[T](initial: T)(f: (T, XmlNode) => T): T = children match {
    case Nil => f(initial, this)
    case xs => children.foldLeft(f(initial,this))((a, b) => b.foldLeft(a)(f))
  }

  override def \(name: String): Option[XmlNode] = children filter {
    case n: Node => n.nodeName equals name
    case _ => false
  } match {
    case Nil => None
    case x :: _ => Some(x)
  }

  override def \\(name: String): List[XmlNode] = this.foldLeft(Nil: List[XmlNode])((l, t) => t match {
    case n: Node =>
      if(n.nodeName equals name)
        l :+ t
      else
        l
    case _ => l
  })

  override def toString() = {
    val a = if(attributes.length == 0) {
      s"<$nodeName>\n"
    }
    else {
      s"<$nodeName ${(attributes map (_.toString)).mkString(" ")}>\n"
    }
    a + s"${(children map (_.toString())).mkString("\n")}" +
    s"</$nodeName>\n"
  }

}
